package com.woparker.kiosk.utils;


import android.os.AsyncTask;


import com.woparker.kiosk.bean.BestPointBean;
import com.woparker.kiosk.bean.MapGroupBean;
import com.woparker.kiosk.bean.NodeBean;
import com.woparker.kiosk.bean.StartEndPointBean;
import com.woparker.kiosk.view.MapViewDraw;
import com.woparker.kiosk.view.QSView;
import com.woparker.kiosk.view.mapview.layer.RouteLayer;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 最优路线搜索
 */
public class SearchTask extends AsyncTask<Object, Integer, List<NodeBean>> {

    //地图数组
    private int[][] map = null;
    private List<NodeBean> openList = new ArrayList<NodeBean>();// 开启列表
    private List<NodeBean> closeList = new ArrayList<NodeBean>();// 关闭列表
    private List<NodeBean> bestRoots = new ArrayList<NodeBean>();// 最优路径
    //起点
    private NodeBean startPoint;
    //终点
    private NodeBean endPoint;
    //行
    private int row;
    //列
    private int col;
    //搜索结果回调
    private QSView qsView;

    //遍历层次超过15个色块则没有合适的通路坐标
    private static final int traverseNumber = 30;


    private static int TILE_HEIGHT_COUNT;
    private static int TILE_WIDTH_COUNT;

    public static float BLOCK_SIZE = 5;


    private final Lock lock = new ReentrantLock();

    public SearchTask(MapGroupBean mapGroupBean) {
        this.map = mapGroupBean.getMap();
        mMapView = mapGroupBean.getMap();
        TILE_HEIGHT_COUNT = mapGroupBean.getCol();
        TILE_WIDTH_COUNT = mapGroupBean.getRow();
        BLOCK_SIZE = mapGroupBean.getBlockSize();

        BLOCK_SIZE = BLOCK_SIZE*BitmapUtils.RATIO;
        MapViewDraw.TILE_WIDTH = BLOCK_SIZE;
        RouteLayer.TILE_WIDTH = BLOCK_SIZE;
    }

    //返回最优路径
    public List<NodeBean> getBestRoot() {
        return bestRoots;
    }

    //清除集合数据
    public void clearn() {
        openList.clear();
        closeList.clear();
        bestRoots.clear();
    }

    /**
     * 搜寻最短路径
     */
    public boolean seachWay(int number, boolean isLast) {
        clearn();
        final int CONST_HENG = 10;// 垂直方向或水平方向移动的路径评分
        final int CONST_XIE = 14;// 斜方向移动的路径评分
        NodeBean curNode = startPoint;
        if (startPoint.x < 0 || startPoint.y > col || endPoint.x < 0
                || endPoint.y > col || map[startPoint.x][startPoint.y] == 0
                || map[endPoint.x][endPoint.y] == 0) {
            throw new IllegalArgumentException("坐标参数错误！！");
        }

        openList.add(startPoint);
        while (!openList.isEmpty() && !openList.contains(endPoint)) {
            curNode = minList(openList);
            if (curNode.x == endPoint.x && curNode.y == endPoint.y
                    || openList.contains(endPoint)) {
                System.out.println("找到最短路径");
                while (!(curNode.x == startPoint.x && curNode.y == startPoint.y)) {
                    bestRoots.add(curNode);
                    // map[curNode.x][curNode.y]=2;
                    if (curNode.parentNode != null) {
                        curNode = curNode.parentNode;
                    }
                }
                if (number >= 0) {
                    //采集最优路线数据
                    qsView.onQueryBestRoot(2, number, bestRoots, isLast);
                } else {
                    //单次查询路线生成
                    qsView.onQueryBestRoot(0, number, bestRoots, isLast);
                }
                // System.out.print("("+startPoint.x+","+startPoint.y+")\n ");
                // map[startPoint.x][startPoint.y]=2;
                return true;
            }
            // 上
            if (curNode.y - 1 >= 0) {
                checkPath(curNode.x, curNode.y - 1, curNode, endPoint,
                        CONST_HENG);
            }
            // 下
            if (curNode.y + 1 < col) {
                checkPath(curNode.x, curNode.y + 1, curNode, endPoint,
                        CONST_HENG);
            }
            // 左
            if (curNode.x - 1 >= 0) {
                checkPath(curNode.x - 1, curNode.y, curNode, endPoint,
                        CONST_HENG);
            }
            // 右
            if (curNode.x + 1 < row) {
                checkPath(curNode.x + 1, curNode.y, curNode, endPoint,
                        CONST_HENG);
            }
            if (CommonUtils.IS_DERECTION_EIGHT) {
                // 左上
                if (curNode.x - 1 >= 0 && curNode.y - 1 >= 0) {
                    checkPath(curNode.x - 1, curNode.y - 1, curNode, endPoint,
                            CONST_XIE);
                }
                // 左下
                if (curNode.x - 1 >= 0 && curNode.y + 1 < col) {
                    checkPath(curNode.x - 1, curNode.y + 1, curNode, endPoint,
                            CONST_XIE);
                }
                // 右上
                if (curNode.x + 1 < row && curNode.y - 1 >= 0) {
                    checkPath(curNode.x + 1, curNode.y - 1, curNode, endPoint,
                            CONST_XIE);
                }
                // 右下
                if (curNode.x + 1 < row && curNode.y + 1 < col) {
                    checkPath(curNode.x + 1, curNode.y + 1, curNode, endPoint,
                            CONST_XIE);
                }
            }
            openList.remove(curNode);
            closeList.add(curNode);
        }
        //单次未查询到路线回调
        qsView.onQueryBestRoot(1, number, bestRoots, isLast);
        return false;

    }

    // 核心算法---检测节点是否通路
    private boolean checkPath(int x, int y, NodeBean preNode, NodeBean endPoint, int c) {
        NodeBean node = new NodeBean(x, y, preNode);
        // 查找地图中是否能通过
        if (map[x][y] == 0) {
            closeList.add(node);
            return false;
        }
        // 查找关闭列表中是否存在
        if (isListContains(closeList, x, y) != -1) {// 存在
            return false;
        }
        // 查找开启列表中是否存在
        int index = -1;
        if ((index = isListContains(openList, x, y)) != -1) {// 存在
            // G值是否更小，即是否更新G，F值
            if ((preNode.g + c) < openList.get(index).g) {
                countG(node, endPoint, c);
                countF(node);
                openList.set(index, node);
            }
        } else {
            // 不存在，添加到开启列表中
            node.parentNode = preNode;
            count(node, endPoint, c);
            openList.add(node);
        }
        return true;
    }

    // 计算G,H,F值
    private static void count(NodeBean node, NodeBean eNode, int cost) {
        countG(node, eNode, cost);
        countH(node, eNode);
        countF(node);
    }

    // 计算G值
    private static void countG(NodeBean node, NodeBean eNode, int cost) {
        if (node.getParentNode() == null) {
            node.g = cost;
        } else {
            node.g = node.parentNode.g + cost;
        }
    }

    // 计算H值
    private static void countH(NodeBean node, NodeBean eNode) {
        node.f = ((Math.abs(node.x - eNode.x) + Math.abs(node.y - eNode.y)) * 10);
    }

    // 计算F值
    private static void countF(NodeBean node) {
        node.f = node.g + node.h;
    }

    // 集合中是否包含某个元素(-1：没有找到，否则返回所在的索引)
    private static int isListContains(List<NodeBean> list, int x, int y) {
        int size = list.size();
        try {
            for (int i = 0; i < size; i++) {
                NodeBean node = list.get(i);
                if (null != node) {
                    if (node.x == x && node.y == y) {
                        return i;
                    }
                }

            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return -1;
    }

    // 找最小值
    private NodeBean minList(List<NodeBean> list) {
        Iterator<NodeBean> i = list.iterator();
        NodeBean candidate = i.next();
        try {
            while (i.hasNext()) {
                NodeBean next = i.next();
                if (next.compareTo(candidate) < 0)
                    candidate = next;
            }
        } catch (java.util.ConcurrentModificationException e) {
            e.printStackTrace();
        }
        return candidate;
    }


    public BestPointBean getQueryBestPoint(int x, int y) {
        BestPointBean bestPoint = new BestPointBean();
        if (x < 0) {
            x = 0;
        }
        if (y < 0) {
            y = 0;
        }
        if (x >= TILE_HEIGHT_COUNT) {
            x = TILE_HEIGHT_COUNT - 1;
        }
        if (y >= TILE_WIDTH_COUNT) {
            y = TILE_WIDTH_COUNT - 1;
        }
        bestPoint.setPointX(x);
        bestPoint.setPointY(y);
        if (SearchTask.mMapView[x][y] == 0) {
            for (int i = 1; i < traverseNumber; i++) {
                if (judgeItem(bestPoint, x, y, i, TILE_WIDTH_COUNT, TILE_HEIGHT_COUNT)) {
                    break;
                }
            }
        }
        return bestPoint;
    }


    //8个方位判断查询最近点
    public boolean judgeItem(BestPointBean bestPoint, int x, int y, int i, int yLength, int xLength) {
        if (SearchTask.mMapView[x][y] == 0) {
            if (x - i > 0) {
                if (SearchTask.mMapView[x - i][y] != 0) {
                    bestPoint.setPointX(x - i);
                    return true;
                }
            }
            if (x + i < xLength) {
                if (SearchTask.mMapView[x + i][y] != 0) {
                    bestPoint.setPointX(x + i);
                    return true;
                }
            }

            if (y - i > 0) {
                if (SearchTask.mMapView[x][y - i] != 0) {
                    bestPoint.setPointY(y - i);
                    return true;
                }
            }
            if (y + i < yLength) {
                if (SearchTask.mMapView[x][y + i] != 0) {
                    bestPoint.setPointY(y + i);
                    return true;
                }
            }
            if (x - i > 0 && y - i > 0) {
                if (SearchTask.mMapView[x - i][y - i] != 0) {
                    bestPoint.setPointX(x - i);
                    bestPoint.setPointY(y - i);
                    return true;
                }
            }
            if (x - i > 0 && y + i < yLength) {
                if (SearchTask.mMapView[x - i][y + i] != 0) {

                    bestPoint.setPointX(x - i);
                    bestPoint.setPointY(y + i);
                    return true;
                }
            }

            if (x + i < xLength && y - i > 0) {
                if (SearchTask.mMapView[x + i][y - i] != 0) {
                    bestPoint.setPointX(x + i);
                    bestPoint.setPointY(y - i);
                    return true;
                }
            }

            if (x + i < xLength && y + i < yLength) {
                if (SearchTask.mMapView[x + i][y + i] != 0) {
                    bestPoint.setPointX(x + i);
                    bestPoint.setPointY(y + i);
                    return true;
                }
            }
        }
        return false;
    }


    /**
     * 获得最优点
     *
     * @param startMX
     * @param startMY
     * @param targetMX
     * @param targetMY
     * @return
     */
    public StartEndPointBean getBestPoint(int startMX, int startMY, int targetMX, int targetMY) {
        int x = (int) ((startMY - BLOCK_SIZE / 2) / BLOCK_SIZE);
        int y = (int) ((startMX - BLOCK_SIZE / 2) / BLOCK_SIZE);
        int tX = (int) ((targetMY - BLOCK_SIZE / 2) / BLOCK_SIZE);
        int tY = (int) ((targetMX - BLOCK_SIZE / 2) / BLOCK_SIZE);
        BestPointBean startXY = getQueryBestPoint(x, y);
        BestPointBean targeXY = getQueryBestPoint(tX, tY);
        return new StartEndPointBean(startXY, targeXY);
    }


    @Override
    protected List<NodeBean> doInBackground(Object... params) {
        this.startPoint = (NodeBean) params[0];
        this.endPoint = (NodeBean) params[1];
        ;
        this.row = TILE_HEIGHT_COUNT;
        this.col = TILE_WIDTH_COUNT;
        this.qsView = (QSView) params[4];
        seachWay((int) params[2], (boolean) params[3]);
        return null;
    }

    @Override
    protected void onPostExecute(List<NodeBean> nodeBeen) {
        super.onPostExecute(nodeBeen);
    }

    public interface OnSearchResultListener {
        void onResultListener(boolean isSuccess);
    }

    //地图路径数据
    public static int[][] mMapView = {

    };


}
